<?php
/**
 * 无状态验证码控制器
 * 不依赖session的JWT兼容验证码方案
 */

declare(strict_types=1);

namespace app\controller;

use think\Response;
use think\facade\Config;

class StatelessCaptchaController
{
    private $width = 120;
    private $height = 40;
    private $length = 4;
    private $font_size = 16;
    
    /**
     * 生成无状态验证码
     * @return \think\response\Json
     */
    public function generate()
    {
        try {
            // 生成验证码文本
            $code = $this->generateCode();
            
            // 创建验证码图片
            $imageData = $this->createImage($code);
            
            // 生成加密的验证码token（包含答案和时间戳）
            $token = $this->encryptCode($code);
            
            return json([
                'code' => 0,
                'msg' => 'success',
                'data' => [
                    'image' => 'data:image/png;base64,' . base64_encode($imageData),
                    'token' => $token,
                    'expire' => time() + 300 // 5分钟过期
                ]
            ]);
            
        } catch (\Exception $e) {
            return json([
                'code' => 1,
                'msg' => '验证码生成失败: ' . $e->getMessage()
            ]);
        }
    }
    
    /**
     * 验证验证码
     * @param string $code 用户输入的验证码
     * @param string $token 验证码token
     * @return \think\response\Json
     */
    public function verify()
    {
        $code = input('code', '');
        $token = input('token', '');
        
        if (empty($code) || empty($token)) {
            return json([
                'code' => 1,
                'msg' => '参数不完整'
            ]);
        }
        
        try {
            $result = $this->verifyCode($code, $token);
            
            if ($result) {
                return json([
                    'code' => 0,
                    'msg' => '验证码正确'
                ]);
            } else {
                return json([
                    'code' => 1,
                    'msg' => '验证码错误或已过期'
                ]);
            }
            
        } catch (\Exception $e) {
            return json([
                'code' => 1,
                'msg' => '验证失败: ' . $e->getMessage()
            ]);
        }
    }
    
    /**
     * 生成验证码字符串
     * @return string
     */
    private function generateCode(): string
    {
        $chars = '23456789ABCDEFGHJKLMNPQRSTUVWXY';
        $code = '';
        for ($i = 0; $i < $this->length; $i++) {
            $code .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $code;
    }
    
    /**
     * 创建验证码图片
     * @param string $code
     * @return string
     */
    private function createImage(string $code): string
    {
        // 创建画布
        $image = imagecreate($this->width, $this->height);
        
        // 定义颜色
        $bg_color = imagecolorallocate($image, 243, 251, 254);
        $text_color = imagecolorallocate($image, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
        $line_color = imagecolorallocate($image, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
        
        // 添加干扰线
        for ($i = 0; $i < 5; $i++) {
            imageline($image, 
                mt_rand(0, $this->width), mt_rand(0, $this->height),
                mt_rand(0, $this->width), mt_rand(0, $this->height),
                $line_color
            );
        }
        
        // 添加噪点
        for ($i = 0; $i < 100; $i++) {
            imagesetpixel($image, 
                mt_rand(0, $this->width), mt_rand(0, $this->height),
                $line_color
            );
        }
        
        // 添加验证码文字
        $x = ($this->width - $this->length * $this->font_size) / 2;
        for ($i = 0; $i < $this->length; $i++) {
            $y = mt_rand($this->height / 2, $this->height - 10);
            imagechar($image, 5, $x + $i * ($this->font_size + 2), $y - 15, $code[$i], $text_color);
        }
        
        // 输出图片数据
        ob_start();
        imagepng($image);
        $imageData = ob_get_contents();
        ob_end_clean();
        
        // 销毁图片资源
        imagedestroy($image);
        
        return $imageData;
    }
    
    /**
     * 加密验证码（包含答案和时间戳）
     * @param string $code
     * @return string
     */
    private function encryptCode(string $code): string
    {
        $data = [
            'code' => strtoupper($code),
            'time' => time()
        ];
        
        $json = json_encode($data);
        $key = Config::get('jwt.key', 'GOUGUOA'); // 使用JWT密钥
        
        // 使用AES加密
        $encrypted = openssl_encrypt($json, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
        return base64_encode($encrypted);
    }
    
    /**
     * 解密并验证验证码
     * @param string $inputCode
     * @param string $token
     * @return bool
     */
    private function verifyCode(string $inputCode, string $token): bool
    {
        try {
            $key = Config::get('jwt.key', 'GOUGUOA');
            
            // 解码和解密
            $encrypted = base64_decode($token);
            $json = openssl_decrypt($encrypted, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
            
            if (!$json) {
                return false;
            }
            
            $data = json_decode($json, true);
            if (!$data || !isset($data['code']) || !isset($data['time'])) {
                return false;
            }
            
            // 检查是否过期（5分钟）
            if (time() - $data['time'] > 300) {
                return false;
            }
            
            // 验证码比较（不区分大小写）
            return strtoupper($inputCode) === strtoupper($data['code']);
            
        } catch (\Exception $e) {
            return false;
        }
    }
}